from flask import Blueprint, make_response, session, request, jsonify, render_template, redirect, g
from utils.captcha.captcha import captcha
from utils.ytx_sdk import ytx_send
import random
from models import UserInfo, db, NewsCategory, NewsInfo
import functools
from utils import qiniu_upload

user_blueprint = Blueprint('user', __name__, url_prefix='/user')


@user_blueprint.route('/image_code')
def image_code():
    # 生成图形验证码
    # name是一个随机生成的字符串
    # text是随机生成的4位字符串，即验证码，这个值会被绘制在图片中
    # image图片的二进制数据
    name, text, image = captcha.generate_captcha()
    # 验证码数据
    print(text)
    # 保存验证码，用于后续的对比
    session['image_code'] = text
    # 创建响应对象
    response = make_response(image)
    # 设置响应数据的类型
    response.mimetype = 'image/png'
    # 返回响应
    return response


@user_blueprint.route('/sms_code')
def sms_code():
    # 接收
    mobile = request.args.get('mobile')
    image_code_request = request.args.get('image_code')
    # 验证
    # 1.验证数据不为空
    if not all([mobile, image_code_request]):
        return jsonify(result=1)  # 数据有空值
    # 2.判断图形验证码是否正确
    # 在取出图形验证码后删除，目的是：防止一直使用同一个验证码向不同手机号不停发短信
    image_code_session = session.pop('image_code')
    if image_code_request != image_code_session:
        return jsonify(result=2)  # 输入验证码不正确
    # 处理:
    # 生成随机的验证码数值
    sms_code_value = str(random.randint(100000, 999999))
    # 保存在session中用于后续验证
    session['sms_code'] = sms_code_value
    # 发短信,mobile表示手机号,[以分为单位的过期时间,验证码],模板编号
    # ytx_send.sendTemplateSMS(mobile, ['5', sms_code_value], 1)
    print(sms_code_value)
    # 响应
    return jsonify(result=3)  # 短信发送成功


@user_blueprint.route('/register', methods=['POST'])
def register():
    # 接收
    mobile = request.form.get('mobile')
    sms_code_request = request.form.get('sms_code')
    pwd = request.form.get('pwd')
    agree = request.form.get('agree')
    # 验证
    if not agree:
        return jsonify(result=3)  # 请勾选同意协议
    if not all([mobile, sms_code_request, pwd]):
        return jsonify(result=1)  # 有空数据
    # 验证短信是否正确
    sms_code_session = session.pop('sms_code')
    if sms_code_session != sms_code_request:
        return jsonify(result=2)  # 短信验证码错误
    # 验证密码长度
    if len(pwd) < 6:
        return jsonify(result=4)  # 密码长度不足6位
    # 验证手机号是否存在,查询结果为0或1
    mobile_exists = UserInfo.query.filter_by(mobile=mobile).count()
    if mobile_exists:
        return jsonify(result=5)  # 手机号存在
    # 处理：创建对象并添加
    user = UserInfo()
    user.nick_name = mobile
    user.mobile = mobile
    user.password = pwd
    # 添加
    db.session.add(user)
    # 提交
    db.session.commit()
    # 响应
    return jsonify(result=6)


@user_blueprint.route('/login', methods=['POST'])
def login():
    # 接收
    mobile = request.form.get('mobile')
    pwd = request.form.get('pwd')
    # 验证
    if not all([mobile, pwd]):
        return jsonify(result=1)
    # 处理
    # 根据手机号查询对象，如果查到则对比密码，如果密码正确则登录成功
    user = UserInfo.query.filter_by(mobile=mobile).first()
    if user:
        # 手机号正确，则对比密码
        if user.check_pwd(pwd):
            # 密码正确
            # 记录用户登录
            session['user_id'] = user.id
            # 返回头像、昵称，以用于展示
            return jsonify(result=3, avatar=user.avatar, nick_name=user.nick_name)
        else:
            # 密码错误
            return jsonify(result=4)
    else:
        # 手机号错误
        return jsonify(result=2)
        # 响应


@user_blueprint.route('/logout')
def logout():
    # 删除session中的登录标记
    session.pop('user_id')
    # 响应
    return jsonify(result=1)


# 使用装饰器的方案进行用户验证判断
def required_login(view_fun):
    # 当使用装饰器加入函数后，函数名称会变为fun1
    # 通过使用@functools.wraps(view_fun)可以返回原函数的名称，而不会改名
    @functools.wraps(view_fun)
    def fun1(*args, **kwargs):
        # 参数*args,**kwargs表示被装饰函数的参数，此处为视图函数的参数
        # 判断是否登录
        if 'user_id' not in session:
            # 如果未登录，则转到首页
            return redirect('/')
        user_id = session.get('user_id')
        # 查询用户对象，保存到全局变量g中
        # g表示一次请求响应的全局变量，在请求时创建，在响应是销毁，每次新请求都是不一样的g对象
        g.user = UserInfo.query.get(user_id)
        # 如果已登录则执行视图函数
        return view_fun(*args, **kwargs)

    return fun1


@user_blueprint.route('/')
@required_login
def index():
    # 当用户登录时，向字典session中添加了键'user_id'
    # 判断用户是否登录，如果未登录则转到首页
    # if 'user_id' not in session:
    #     return redirect('/')
    # # 获取当前登录的用户编号
    # user_id = session.get('user_id')
    # # 根据编号查询用户对象
    # user = UserInfo.query.get(user_id)
    # 交给模板展示数据
    return render_template(
        'news/user.html',
        # user=user,
        title='用户中心')


@user_blueprint.route('/base', methods=["GET", 'POST'])
@required_login
def base():
    # 判断用户是否登录
    # 查询用户对象，展示数据，用于修改
    user = UserInfo.query.get(session.get('user_id'))
    # get请求方式，展示数据
    if request.method == 'GET':
        return render_template('news/user_base_info.html', user=user)
    # post请求方式，进行数据修改
    signature = request.form.get('signature')
    nick_name = request.form.get('nick_name')
    gender = request.form.get('gender')

    if not all([nick_name, gender]):
        return jsonify(result=1)  # 数据不完整
    # 进行性别字符串到bool类型的转换
    gender = bool(int(gender))  # '1'或'0'==>1或0
    # 修改对象的属性
    user.signature = signature
    user.nick_name = nick_name
    user.gender = gender
    # 提交到数据库
    db.session.commit()
    # 响应
    return jsonify(result=2)


@user_blueprint.route('/release', methods=['GET', 'POST'])
@required_login
def release():
    if request.method == 'GET':
        # 查询所有分类，在页面中显示，供用户选择
        category_list = NewsCategory.query.all()
        return render_template(
            'news/user_news_release.html',
            category_list=category_list
        )
    # post请求进行新闻添加
    # 接收
    dict1 = request.form
    title = dict1.get('title')
    category = dict1.get('category')
    summary = dict1.get('summary')
    content = dict1.get('content')
    # 接收文件
    pic = request.files.get('pic')
    # 验证
    if not all([title, category, summary, content, pic]):
        return '数据不能为空'
    # 处理
    # 1.将文件保存到七牛，并获取图片名称
    pic_name = qiniu_upload.upload(pic)
    # 2.新建新闻对象
    news = NewsInfo()
    news.title = title
    news.category_id = int(category)
    news.summary = summary
    news.context = content
    news.pic = pic_name
    news.user_id = session.get('user_id')
    # 保存
    db.session.add(news)
    db.session.commit()
    # 响应
    return redirect('/user/list')
